<template>
  <div class="content grid-layout-design">
    <div class="tabsHeader">
      <div>
        <div
          :class="{ mainTitle: chartOptions.mainTitle !== '' }"
          :title="chartOptions.mainTitle"
        >
          {{ chartOptions.mainTitle }}
        </div>
      </div>
      <span
        v-show="tabsPrevNextIconVisible"
        class="tabs-prev-icon"
        @click="handleTabsPrev"
        ><a-icon-font type="iconicon-beifen-right"
      /></span>
      <div ref="tabsList" class="tabsList">
        <div
          v-for="(tab, index) in tabs"
          :key="tab.id"
          class="subTitle"
          :class="{ active: isActiveTab(tab.id) }"
          @drop.stop="drop(index)"
          @dragstart="dragstart(index)"
        >
          <div v-if="!isEditState(tab.id)">
            <a-icon-font
              draggable="true"
              :class="{ hideIcon: isNotAllowed }"
              class="subTitleIcon icontuodong"
              type="icontuodong"
            ></a-icon-font>
            <span
              class="subTitleText"
              @dblclick="startEditTitle(tab.id)"
              @click="switchTab(tab.id)"
              >{{ tab.title }}</span
            >
            <a-icon-font
              :class="{ hideIcon: isNotAllowed }"
              class="subTitleIcon"
              type="iconbianjizhi"
              @click="startEditTitle(tab.id)"
            ></a-icon-font>
            <a-dropdown
              :class="{ hideIcon: isNotAllowed }"
              :trigger="['click']"
            >
              <a-icon-font
                class="subTitleIcon"
                type="icondiandian"
              ></a-icon-font>
              <a-menu slot="overlay">
                <a-menu-item key="1" @click="copyTab(tab, index)"
                  >复制页面</a-menu-item
                >
                <a-menu-item key="2" @click="deleteTab(tab, index)"
                  >删除该页面</a-menu-item
                >
              </a-menu>
            </a-dropdown>
          </div>
          <a-input
            v-else
            v-model="tab.title"
            v-focus
            class="editTitle"
            @keyup.enter="completeEditTitle()"
            @blur="completeEditTitle()"
          ></a-input>
        </div>
        <div v-if="!isNotAllowed" class="createTab" @click="createTab">
          <a-icon-font type="iconjiahao"></a-icon-font>
        </div>
      </div>
      <span
        v-show="tabsPrevNextIconVisible"
        class="tabs-next-icon"
        @click="handleTabsNext"
        ><a-icon-font type="iconicon-beifen-right"
      /></span>
    </div>
    <widgets-layout
      ref="widgetLayout"
      class="tabs-content"
      :layout="layout"
      :show-scroll="true"
      target-container="tabs"
    />
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import { GridItemDataInterface } from '../vueGridLayout/interfate/grid-Item-data-inteface'
import VisualizationStore from '@/store/modules/visualization'
import VisualizationPreviewStore from '@/store/modules/visualization-preview'
import UserStore from '@/store/modules/user'
import { saveWidgetBatch, deleteWidgetBatch } from '@/api/widget'
import { buildSaveParameters } from '@/util/common'
import { cloneDeep } from 'lodash'
import { VisTabType } from './vistabs-interface'

@Component({
  components: {},
  directives: {
    focus: {
      inserted: (element: any) => {
        element.focus()
      },
    },
  },
})
export default class VisTabs extends Vue {
  @Prop({}) itemData!: GridItemDataInterface

  private dragTabIndex = -1
  private editState = false
  private tabsPrevNextIconVisible: boolean = false // tabs前后点击icon是否显示

  get dataStore() {
    if (this.isPreview) {
      return VisualizationPreviewStore
    }
    return VisualizationStore
  }

  mounted() {
    this.itemData.chartOptions.activeTabId = this.itemData.chartOptions.tabs[0].id
  }

  get layout() {
    const { activeTabId } = this.itemData.chartOptions
    return this.dataStore.gridList.filter(
      (gridItem) => gridItem.chartOptions.parentId === activeTabId
    )
  }

  get tabs(): Array<VisTabType> {
    return this.itemData.chartOptions.tabs
  }

  get chartOptions() {
    return this.itemData.chartOptions
  }

  get isNotAllowed() {
    return this.isVisitor || this.isPreview || this.isPublish
  }

  get isVisitor() {
    //  访客身份
    return UserStore.isProjectGuest
  }

  get isPreview() {
    // 预览状态
    return VisualizationStore.visualizationMode === 'preview'
  }

  get isPublish() {
    // 发布状态
    return VisualizationStore.visualizationMode === 'publish'
  }

  get projectId() {
    return (this.$route.params as any).id || localStorage.getItem('projectId')
  }

  get dashBoardId() {
    return this.dataStore.currentDashboard.id
  }
  @Watch('tabs', { immediate: true })
  private onTabsChange() {
    this.isShowTabsPrevNextIcon()
  }

  private getGridSubItemsByParentId(parentId: string) {
    return this.dataStore.gridList.filter(
      (gridItem) => gridItem.chartOptions.parentId === parentId
    )
  }

  private dragstart(tabIndex: number) {
    this.dragTabIndex = tabIndex
  }

  private drop(dropTabIndex: number) {
    if (this.dragTabIndex === dropTabIndex) {
      return
    }

    const dragTab = this.chartOptions.tabs[this.dragTabIndex]
    if (this.dragTabIndex > dropTabIndex) {
      this.chartOptions.tabs.splice(this.dragTabIndex, 1)
      this.chartOptions.tabs.splice(dropTabIndex, 0, dragTab)
    } else if (this.dragTabIndex < dropTabIndex) {
      this.chartOptions.tabs.splice(dropTabIndex + 1, 0, dragTab)
      this.chartOptions.tabs.splice(this.dragTabIndex, 1)
    }

    this.dragTabIndex = -1
    this.updateTabsWidget()
  }

  private switchTab(tabId: string) {
    if (this.itemData.chartOptions.activeTabId === tabId) {
      return
    }

    this.itemData.chartOptions.activeTabId = tabId

    // 切换tab后调整组件的大小，避免隐藏状态下tabs组件大小改变带来的影响
    const widgetLayout = this.$refs.widgetLayout as any
    // 预览/发布/游客状态下，不需要调整布局大小，只有可编辑状态下才需要调整布局大小
    // NAP-4951:切换tab导致的折线图展示混乱，是因为在widgetLayout中通过this.$set修改size所致
    if (!this.isNotAllowed && widgetLayout) {
      setTimeout(() => {
        widgetLayout.resizedAllItems()
      }, 10)
    }
  }

  private updateTabsWidget() {
    const index = this.dataStore.gridList.findIndex(
      (gridItem) => gridItem.i === this.itemData.i
    )
    this.dataStore.updateWidget({ gridItem: this.itemData, index })
  }

  private startEditTitle(tabId: string) {
    if (!this.isNotAllowed) {
      this.editState = true
    }

    this.switchTab(tabId)
  }

  private completeEditTitle() {
    this.editState = false

    this.updateTabsWidget()
  }

  private isActiveTab(tabId: string) {
    return this.itemData.chartOptions.activeTabId === tabId
  }

  private isEditState(tabId: string) {
    return tabId === this.itemData.chartOptions.activeTabId && this.editState
  }

  private createTab() {
    const { tabs } = this.itemData.chartOptions
    const tabId = `vistabs-tab-${Math.random().toString(36).slice(-8)}`
    tabs.push({
      id: tabId,
      title: `页面${tabs.length + 1}`,
    })
    this.itemData.chartOptions.activeTabId = tabId
    this.updateTabsWidget()
    this.$nextTick(() => {
      this.handleTabsNext()
    })
  }

  private updateActiveTabAfterDelete(
    deleteTabId: string,
    deleteTabIndex: number
  ) {
    // 如果当前删除的Tab是激活状态
    if (deleteTabId === this.itemData.chartOptions.activeTabId) {
      const nextActiveTabIndex: number =
        deleteTabIndex < 1 ? deleteTabIndex : deleteTabIndex - 1
      this.itemData.chartOptions.activeTabId = this.itemData.chartOptions.tabs[
        nextActiveTabIndex
      ].id
    }
  }

  private deleteTab(tab: any, index: number) {
    if (this.itemData.chartOptions.tabs.length <= 1) {
      this.$message.info('只有一个tab时不能删除')
      return
    }

    const tabItems = this.getGridSubItemsByParentId(tab.id)
    if (tabItems.length <= 0) {
      const deleteTabId = this.itemData.chartOptions.tabs[index].id
      this.itemData.chartOptions.tabs.splice(index, 1)
      this.updateTabsWidget()
      this.updateActiveTabAfterDelete(deleteTabId, index)
    } else {
      this.$confirm({
        content: '该页面含有图表或控件内容，是否确认删除？',
        onOk: () => {
          this.confirmDelete(index)
        },
      })
    }
  }

  private confirmDelete(deleteTabIndex: number) {
    const widgetIds: any = []
    const deleteTabId = this.itemData.chartOptions.tabs[deleteTabIndex].id
    const { gridList } = this.dataStore
    const tabItems = this.getGridSubItemsByParentId(deleteTabId).map(
      (item) => item.i
    )

    for (let i = gridList.length - 1; i >= 0; i -= 1) {
      const gridItem = gridList[i]
      if (tabItems?.includes(gridItem.i.toString())) {
        if (gridItem.widgetId) {
          // 如果已生成widgetId，则获取要删除的item.widgetId
          widgetIds.push(gridItem.widgetId)
        }

        // 删除元素
        this.dataStore.removeGridItem(i, 1)
      }
    }

    this.itemData.chartOptions.tabs.splice(deleteTabIndex, 1)
    this.updateTabsWidget()

    if (widgetIds.length > 0) {
      deleteWidgetBatch({
        data: {
          projectId: this.projectId,
          widgetIds,
        },
      }).then(() => {
        this.dataStore.eventBus.$emit('widget-on-save')
      })
    }

    this.updateActiveTabAfterDelete(deleteTabId, deleteTabIndex)
  }

  private async copyTab(tab: any, index: number) {
    // 创建tab，并保存tab信息
    const { tabs } = this.itemData.chartOptions
    const tabId = `vistabs-tab-${Math.random().toString(36).slice(-8)}`
    this.itemData.chartOptions.activeTabId = tabId
    tabs.splice(index + 1, 0, {
      id: tabId,
      title: `${tab.title}（复制）`,
    })
    this.updateTabsWidget()

    // 整理要复制的item数据，提交后端获取widgetId
    const tabItemIds = this.getGridSubItemsByParentId(tab.id).map(
      (item) => item.i
    )
    const items: any = []
    const widgets: any = []
    const oldWidgetIds: any = [] // 保存旧的widgetId，便于后续与新的widgetId对应上
    this.dataStore.gridList.forEach((gridItem) => {
      if (tabItemIds?.includes(gridItem.i.toString())) {
        oldWidgetIds.push(gridItem.widgetId)
        const copyItem = cloneDeep(gridItem)
        const item = {
          ...copyItem,
          chartOptions: {
            ...copyItem.chartOptions,
            parentId: tabId,
            title: `${copyItem.chartOptions.title}（复制）`,
          },
          i: this.generateItemId(copyItem.chartType),
          widgetId: '',
        }
        items.push(item)
        const parameter = buildSaveParameters(item)
        parameter.data.dashBoardId = this.dashBoardId
        widgets.push(parameter.data)
      }
    })

    const response = await saveWidgetBatch({
      data: {
        projectId: this.projectId,
        widgets,
      },
    })
    const newWidgetIds = response.data.result

    // 更新widgetId信息，并更新数据到store(gridList)中
    items.forEach((item: any, itemIndex: number) => {
      // 更新widgetId
      item.widgetId = newWidgetIds[itemIndex]

      // 针对筛选器的关联图表处理：如果该item有关联图表，将旧的widgetId替换为新的widgetId
      if (item.chartOptions.associationChart) {
        const { associationChart } = item.chartOptions
        associationChart.forEach((widgetId: number, chartIndex: number) => {
          const oldWidgetIdIndex = oldWidgetIds.findIndex(
            (oldWidgetId: number) => oldWidgetId === widgetId
          )
          associationChart[chartIndex] = newWidgetIds[oldWidgetIdIndex]
        })
      }

      // 针对通过pipeline创建的图表关联关系处理：
      if (item.interactionJson && item.interactionJson.relateWidgets) {
        const { relateWidgets } = item.interactionJson
        relateWidgets.forEach((relateWidget: any, widgetIndex: number) => {
          const oldWidgetIdIndex = oldWidgetIds.findIndex(
            (oldWidgetId: number) => oldWidgetId === relateWidget.widgetId
          )
          relateWidgets[widgetIndex].widgetId = newWidgetIds[oldWidgetIdIndex]
        })
      }

      // 将新创建的gridItem添加到gridList中
      this.dataStore.addGridItem(item)
    })

    // 保存dashboard
    this.dataStore.eventBus.$emit('widget-on-save')
  }

  private generateItemId(chartType: string | string[]) {
    const prefix = Array.isArray(chartType) ? chartType[0] : chartType
    return `${prefix}${Math.random().toString(36).slice(-8)}`
  }

  // 点击向前按钮
  private handleTabsPrev() {
    const $tabsList: Element | undefined = this.$refs.tabsList as Element
    if ($tabsList && $tabsList.scrollLeft > 0) {
      $tabsList.scrollLeft -= 150
    }
  }

  // 点击向前后按钮
  private handleTabsNext() {
    const $tabsList: Element | undefined = this.$refs.tabsList as Element
    if ($tabsList) {
      $tabsList.scrollLeft += 150
    }
  }
  /**
   * 是否显示前后点击icon
   * scrollWidth > clientWidth
   */
  private isShowTabsPrevNextIcon() {
    setTimeout(() => {
      if (this.$refs.tabsList) {
        const { scrollWidth, clientWidth } = this.$refs.tabsList as Element
        this.tabsPrevNextIconVisible = scrollWidth > clientWidth
      } else {
        this.tabsPrevNextIconVisible = false
      }
    }, 100)
  }

  public flexLayout() {
    const widgetLayout = this.$refs.widgetLayout as any
    if (widgetLayout) {
      widgetLayout.flexLayout()
    }
  }
}
</script>

<style lang="less" scoped>
.content {
  height: 100%;
}

.tabsHeader {
  border-bottom: 1px solid #ccc;
  color: var(--title-color);
  display: flex;
  padding: 10px;
  padding-right: 40px;
}

.mainTitle {
  border-right: 1px solid #ccc;
  max-width: 200px;
  overflow: hidden;
  padding-right: 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tabsList {
  display: flex;
  flex: 1;
  justify-content: flex-start;
  margin-right: 4px;
  overflow: hidden;
}

.tabs-prev-icon,
.tabs-next-icon {
  color: var(--controller-palceholder);
  cursor: pointer;
  padding: 0 4px;

  &:hover {
    color: #5561ff;
  }
}

.tabs-prev-icon {
  transform: rotate(180deg);
}

.createTab {
  cursor: pointer;
  padding: 0 3px;

  &:hover {
    background-color: #efefef;
    border-radius: 10px;
  }
}

.subTitleText {
  cursor: pointer;
}

.subTitleIcon {
  font-size: 12px;
  padding-left: 3px;
  visibility: hidden;
}

.icontuodong {
  cursor: move;
}

.editTitle {
  height: 20px;
  padding: 0;
  width: 75px;
}

.subTitle {
  margin-right: 8px;
  padding: 0 2px;
  white-space: nowrap;

  &.active {
    color: #5561ff;
  }

  &:hover {
    .subTitleIcon {
      visibility: visible;

      &.hideIcon {
        visibility: hidden;
      }
    }
  }
}

.tabs-content {
  background-color: var(--tabcontent-bg-color);
}
</style>
